library UnitUtils requires  /*
    */ BonusMod /*
    */ Practicals /*
    */ Constants /*
    */ Dto /*
    */ Unit /*
    */

    globals
        private constant real INTERVAL = .03125
    endglobals

    struct UnitUtils extends array
        

        /*
        --------------------------------------------------------------------------
        # 延迟发送非目标指令给单位
        --------------------------------------------------------------------------
        * param  unit    u             单位
        * param  integer orderId       指令ID
        * param  real    delay         延迟时间
        */
        private static method anon_7b2ec936db9f takes nothing returns nothing
            local Dto dto = GetTimerData(GetExpiredTimer())
            call IssueImmediateOrderById(dto.m_unit, dto.m_int)
            call dto.destroy()
        endmethod
        static method delayIssueImmediateOrderById takes unit u, integer orderId, real delay returns nothing
            local Dto dto = Dto.create()
            set dto.m_unit = u
            set dto.m_int = orderId
            call TimerStart(dto.getTimer(), delay, false, function thistype.anon_7b2ec936db9f)
        endmethod

        /*
        --------------------------------------------------------------------------
        # 延迟发送目标指令给单位
        --------------------------------------------------------------------------
        * param  unit    u             单位
        * param  integer orderId       指令ID
        * param  unit    ua            目标单位
        * param  real    delay         延迟时间
        */
        private static method anon_29d87b78 takes nothing returns nothing
            local Dto dto = GetTimerData(GetExpiredTimer())
            call IssueTargetOrderById(dto.m_unit, dto.m_int, dto.m_unit1)
            call dto.destroy()
        endmethod
        static method delayIssueTargetOrderById takes unit u, integer orderId, unit ua, real delay returns nothing
            local Dto dto = Dto.create()
            set dto.m_unit = u
            set dto.m_unit1 = ua
            set dto.m_int = orderId
            call TimerStart(dto.getTimer(), delay, false, function thistype.anon_29d87b78)
        endmethod
        
        /*
        --------------------------------------------------------------------------
        # 延迟删除单位
        --------------------------------------------------------------------------
        * param 
        */
        private static method anon_421136c4a7af takes nothing returns nothing
            local Dto dto = GetTimerData(GetExpiredTimer())
            call Unit.get(dto.m_unit).destroy()
            call RemoveUnit(dto.m_unit)
            call dto.destroy()
        endmethod
        static method delayRemoveUnit takes unit u, real delay returns nothing
            local Dto dto = Dto.create()
            set dto.m_unit = u
            call TimerStart(dto.getTimer(), delay, false, function thistype.anon_421136c4a7af)
        endmethod

        /*
        --------------------------------------------------------------------------
        # 延迟增加物体的生命，可为负数
        --------------------------------------------------------------------------
        * param 
        */
        private static method anon_2603262b1684 takes nothing returns nothing
            local Dto dto = GetTimerData(GetExpiredTimer())
            local real currLife = GetWidgetLife(dto.m_unit)
            call SetWidgetLife(dto.m_unit, currLife + dto.m_real)
            call dto.destroy()
        endmethod
        static method delayAddWidgetLife takes unit u, real rec, real delay returns nothing
            local Dto dto = Dto.create()
            set dto.m_unit = u
            set dto.m_real = rec
            call TimerStart(dto.getTimer(), delay, false, function thistype.anon_2603262b1684)
        endmethod

        /*
        --------------------------------------------------------------------------
        # 延迟设置单位生命/魔法
        --------------------------------------------------------------------------
        * param unit u
        * param real newValue
        * param real delay
        */
        private static method anon_7383b4b66b47 takes nothing returns nothing
            local Dto dto = GetTimerData(GetExpiredTimer())
            local unitstate whichUnitState = UNIT_STATE_LIFE
            if dto.m_int == 0 then
                set whichUnitState = UNIT_STATE_LIFE
            elseif dto.m_int == 1 then
                set whichUnitState = UNIT_STATE_MANA
            endif
            call SetUnitState(dto.m_unit, whichUnitState, RMaxBJ(0, dto.m_real))
            call dto.destroy()
            set whichUnitState = null
        endmethod

        private static method delaySetUnitState takes unit u, integer state, real newValue, real delay returns nothing
            local Dto dto = Dto.create()
            set dto.m_unit = u
            set dto.m_int = state
            set dto.m_real = newValue
            call TimerStart(dto.getTimer(), delay, false, function thistype.anon_7383b4b66b47)
        endmethod
        
        static method delaySetUnitLife takes unit u, real newValue, real delay returns nothing
            call delaySetUnitState(u, 0, newValue, delay)
        endmethod

        static method delaySetUnitMana takes unit u, real newValue, real delay returns nothing
            call delaySetUnitState(u, 1, newValue, delay)
        endmethod

        /*
        --------------------------------------------------------------------------
        # 限时增加单位属性
        --------------------------------------------------------------------------
        * param 
        */
        private static method anon_f60785ff takes nothing returns nothing
            local Dto dto = GetTimerData(GetExpiredTimer())
            local Bonus whichBonus = dto.m_data
            call AddUnitBonus(dto.m_unit, whichBonus, - dto.m_int)
            call dto.destroy()
        endmethod
        static method addUnitBonusTimed takes unit u, Bonus whichBonus, integer value, real timeout returns nothing
            local Dto dto = Dto.create()
            set dto.m_unit = u
            set dto.m_data = integer(whichBonus)
            set dto.m_int = value
            call AddUnitBonus(u, whichBonus, value)
            call TimerStart(dto.getTimer(), timeout, false, function thistype.anon_f60785ff)
        endmethod

        /*
        --------------------------------------------------------------------------
        # 设置单位限时无敌
        --------------------------------------------------------------------------
        * @param unit u
        * @param real timeout 限时时间
        */
        private static method anon_1404460bcd1a takes nothing returns nothing
            local Dto dto = ReleaseTimer(GetExpiredTimer())
            call SetUnitInvulnerable(dto.m_unit, false)
            call dto.destroy()
        endmethod

        static method setUnitInvulnerableTimed takes unit u, real timeout returns nothing
            local Dto dto = Dto.create()
            set dto.m_unit = u
            call SetUnitInvulnerable(u, true)
            call TimerStart(dto.getTimer(), timeout, false, function thistype.anon_1404460bcd1a)
        endmethod

        /*
        --------------------------------------------------------------------------
        # 设置单位魔法免疫-可限时
        --------------------------------------------------------------------------
        * param  unit u
        * param  real timeout 限时时间, 0 表示无限
        */
        static method disableUnitMagicImmunity takes unit u returns nothing
            call UnitRemoveAbility(u, 'MaIm')
        endmethod

        static method enableUnitMagicImmunity takes unit u returns nothing
            call UnitAddAbility(u, 'MaIm')
            call UnitMakeAbilityPermanent(u, true, 'MaIm')
            call SetPlayerAbilityAvailable(GetOwningPlayer(u), 'MaIm', false)
        endmethod
        
        private static method anon_5ad4581d7069 takes nothing returns nothing
            local Dto dto = GetTimerData(GetExpiredTimer())
            call disableUnitMagicImmunity(dto.m_unit)
            call dto.destroy()
        endmethod

        static method setUnitMagicImmunityTimed takes unit u, real timeout returns nothing
            local Dto dto = Dto.create()
            set dto.m_unit = u
            
            call enableUnitMagicImmunity(u)

            call TimerStart(dto.getTimer(), timeout, false, function thistype.anon_5ad4581d7069)
        endmethod

        /*
        --------------------------------------------------------------------------
        # 延迟重置单位动画
        --------------------------------------------------------------------------
        * param 
        */
        private static method anon_e95c9a6e52f0 takes nothing returns nothing
            local Dto dto = GetTimerData(GetExpiredTimer())
            call ResetUnitAnimation(dto.m_unit)
            call dto.destroy()
        endmethod

        static method delayResetUnitAnimation takes unit u, real time returns nothing
            local Dto dto = Dto.create()
            set dto.m_unit = u
            call TimerStart(dto.getTimer(), time, false, function thistype.anon_e95c9a6e52f0)
        endmethod

        /*
        --------------------------------------------------------------------------
        # 延迟播放单位动作-根据动画序号
        --------------------------------------------------------------------------
        * param unit u
        * param integer index
        * param real time
        * param real resetTime
        */
        private static method anon_f9136c45a231 takes nothing returns nothing
            local Dto dto = GetTimerData(GetExpiredTimer())
            call SetUnitAnimationByIndex(dto.m_unit, dto.m_int)
            if dto.m_real > 0 then
                call UnitUtils.delayResetUnitAnimation(dto.m_unit, dto.m_real)
            endif
            call dto.destroy()
        endmethod
        static method delaySetUnitAnimationByIndex takes unit u, integer index, real time, real resetTime returns nothing
            local Dto dto = Dto.create()
            set dto.m_unit = u
            set dto.m_int = index
            set dto.m_real = resetTime
            call DisableUnitTimed(u, time + resetTime)
            call TimerStart(dto.getTimer(), time, false, function thistype.anon_f9136c45a231)
        endmethod

        /*
        --------------------------------------------------------------------------
        # 延迟播放单位动作-根据动画名称
        --------------------------------------------------------------------------
        * param unit u
        * param string animationName
        * param real time
        * param real resetTime
        */
        private static method anon_e16e691aa798 takes nothing returns nothing
            local Dto dto = GetTimerData(GetExpiredTimer())
            call SetUnitAnimation(dto.m_unit, dto.m_string)
            if dto.m_real > 0 then
                call UnitUtils.delayResetUnitAnimation(dto.m_unit, dto.m_real)
            endif
            call dto.destroy()
        endmethod
        static method delaySetUnitAnimation takes unit u, string animationName, real time, real resetTime returns nothing
            local Dto dto = Dto.create()
            set dto.m_unit = u
            set dto.m_string = animationName
            set dto.m_real = resetTime
            call DisableUnitTimed(u, time + resetTime)
            call TimerStart(dto.getTimer(), time, false, function thistype.anon_e16e691aa798)
        endmethod

        /*
        --------------------------------------------------------------------------
        # 跳跃函数
        --------------------------------------------------------------------------
        * param unit     u
        * param real     angle     角度
        * param real     distance  距离
        * param real     lasttime  持续时间
        * param real     heightMax 最大高度
        * param real     dcHeight  最大容许公差高度(单位高度与点高度之差)
        * param integer  data      绑定数据
        * param CallBack callback  回调函数
        */
        private static method anon_17eb093a384b takes nothing returns nothing
            local Dto dto = GetTimerData(GetExpiredTimer())
            local real angle = dto.getReals(0)
            local real heightMax = dto.getReals(3)
            local real step = dto.getReals(4)
            local real recR = dto.getReals(5)
            local real flyHeight = dto.getReals(6)
            local integer count = dto.getIntegers(1)
            local real stepX = dto.m_real1
            local real stepY = dto.m_real2
            local real X = 0.00
            local real Y = 0.00
            local real Z = 0.00
            local real Hdc = 0.00
            local real height = 0.00
            local CallBack callback
            if count < dto.getIntegers(0) then
                set count = count + 1
                call dto.setIntegers(1, count)
                set X = dto.getReals(1) + count * stepX
                set Y = dto.getReals(2) + count * stepY
                set Hdc = GetUnitZ(dto.m_unit) - GetSurfaceZ(X, Y)
                if (Hdc >- dto.getReals(7)) and (not (IsBeyondBound(X, Y))) then
                    call SetUnitX(dto.m_unit, X)
                    call SetUnitY(dto.m_unit, Y)
                    set height = (- (2 * I2R(count) * recR - 1) * (2 * I2R(count) * recR - 1) + 1) * heightMax + flyHeight
                    call SetUnitFlyHeight(dto.m_unit, height, 0.00)
                else
                    call SetUnitFlyHeight(dto.m_unit, flyHeight, 0.00)
                    set callback = CallBack(dto.m_int)
                    if callback != 0 then
                        call callback.evaluate(dto.m_data)
                    endif
                    call dto.destroy()
                endif
            else
                set callback = dto.m_int
                if callback != 0 then
                    call callback.evaluate(dto.m_data)
                endif
                call SetUnitFlyHeight(dto.m_unit, flyHeight, 0.00)
                call dto.destroy()
            endif
        endmethod
        static method unitJumpTo takes unit u, real angle, real distance, real lasttime, real heightMax, real dcHeight, integer data, CallBack callback returns nothing
            local Dto dto = Dto.create()
            local integer lastLength = R2I(lasttime / 0.02)
            local real step

            set dto.m_unit = u
            set dto.m_data = data
            set dto.m_int = integer(callback)
            call dto.setReals(0, angle)
            call dto.setReals(1, GetUnitX(u))
            call dto.setReals(2, GetUnitY(u))
            call dto.setReals(3, heightMax)
            set step = distance / lastLength
            call dto.setReals(4, step)
            call dto.setReals(5, 1.0 / lastLength)
            call dto.setReals(6, GetUnitFlyHeight(u))
            call dto.setReals(7, dcHeight)
            set dto.m_real1 = step * Cos(angle * bj_DEGTORAD)
            set dto.m_real2 = step * Sin(angle * bj_DEGTORAD)
            call dto.setIntegers(0, lastLength)
            call dto.setIntegers(1, 0)

            call TimerStart(dto.getTimer(), 0.02, true, function thistype.anon_17eb093a384b)
        endmethod

        /*
        --------------------------------------------------------------------------
        # 冲锋函数(单位)
        --------------------------------------------------------------------------
        * param unit     u
        * param unit     ua        冲锋目标
        * param integer  faceModel 朝向模式(0:朝向冲锋单位, 1:反向冲锋单位)
        * param real     initSpeed 初始速度
        * param real     maxSpeed  最大速度
        * param real     acc       加速度
        * param string   eff       冲锋时特效
        * param real     et        冲锋时特效创建间隔
        * param integer  data      绑定数据
        * param CallBack callback  回调函数
        */
        private static method anon_0f48f926af63 takes nothing returns nothing
            local Dto dto = GetTimerData(GetExpiredTimer())
            local real ux = GetUnitX(dto.m_unit)
            local real uy = GetUnitY(dto.m_unit)
            local real step = dto.getReals(0)
            local real maxStep = dto.getReals(1)
            local real et = dto.getReals(3)
            local integer count = dto.getIntegers(0)
            local integer faceModel = dto.getIntegers(1)
            local real ang = GetAngleByXY(ux, uy, GetUnitX(dto.m_unit1), GetUnitY(dto.m_unit1))
            local real dis = GetDistanceByXY(ux, uy, GetUnitX(dto.m_unit1), GetUnitY(dto.m_unit1))
            local real x
            local real y
            local CallBack callback = 0
            if count > 0 then
                set count = count - 1
                call dto.setIntegers(0, count)
                if step < maxStep then
                    set step = step + dto.getReals(2)
                    call dto.setReals(0, step)
                else
                    call dto.setReals(0, maxStep)
                endif
                set x = ux + GetDistanceX(step, ang)
                set y = uy + GetDistanceY(step, ang)
                call SetUnitX(dto.m_unit, x)
                call SetUnitY(dto.m_unit, y)
                if faceModel == 0 then
                    call SetUnitFacing(dto.m_unit, ang)
                elseif faceModel == 1 then
                    call SetUnitFacing(dto.m_unit, ang + 180.0)
                endif
                if dto.m_string != null and et > 0.0 then
                    if ModuloInteger(count, R2I(et / INTERVAL)) == 0 then
                        call DestroyEffect(AddSpecialEffectTarget(dto.m_string, dto.m_unit, "origin"))
                    endif
                endif
                if dis < XE_MAX_COLLISION_SIZE then
                    set callback = dto.m_int
                    if callback != 0 then
                        call callback.evaluate(dto.m_data)
                    endif
                    call dto.destroy()
                endif
            else
                set callback = dto.m_int
                if callback != 0 then
                    call callback.evaluate(dto.m_data)
                endif
                call dto.destroy()
            endif
        endmethod
        static method unitChargeToUnit takes unit u, unit ua, integer faceModel, real initSpeed, real maxSpeed, real acc, string eff, real et, integer data, CallBack callback returns nothing
            local Dto dto = Dto.create()
            local real dis = GetDistanceByUnitXY(u, ua)
            local real avgspeed = (initSpeed + maxSpeed) / 2
            set dto.m_unit = u
            set dto.m_unit1 = ua
            set dto.m_data = data
            set dto.m_int = integer(callback)
            set dto.m_string = eff
            call dto.setReals(0, initSpeed * INTERVAL)
            call dto.setReals(1, maxSpeed * INTERVAL)
            call dto.setReals(2, acc * INTERVAL * INTERVAL)
            call dto.setReals(3, et)
            call dto.setIntegers(0, R2I(dis / (avgspeed * INTERVAL)))
            call dto.setIntegers(1, faceModel)
            call TimerStart(dto.getTimer(), INTERVAL, true, function thistype.anon_0f48f926af63)
        endmethod

        /*
        --------------------------------------------------------------------------
        # 冲锋函数(坐标)
        --------------------------------------------------------------------------
        * param  unit     u
        * param  real     x          坐标x
        * param  real     y          坐标y
        * param  integer  faceModel  朝向模式(0:朝向冲锋坐标, 1:反向冲锋坐标)
        * param  real     initSpeed  初始速度
        * param  real     maxSpeed   最大速度
        * param  real     acc        加速度
        * param  boolean  isTerrian  是否无视地形
        * param  boolean  isObstacle 是否无视障碍
        * param  string   eff        冲锋时特效
        * param  real     et         冲锋时特效间隔
        * param  integer  data       绑定数据
        * param  CallBack callback   回调函数
        */
        private static method anon_dc1095a3d366 takes nothing returns nothing
            call KillDestructable(GetFilterDestructable())
        endmethod
        private static method anon_2da922d02b6b takes nothing returns nothing
            local Dto dto = GetTimerData(GetExpiredTimer())
            local integer faceModel = dto.getIntegers(1)
            local integer count = dto.getIntegers(0)
            local real step = dto.getReals(2)
            local real maxStep = dto.getReals(3)
            local real chargeX = dto.getReals(0)
            local real chargeY = dto.getReals(1)
            local real ang = GetAngleByXY(GetUnitX(dto.m_unit), GetUnitY(dto.m_unit), chargeX, chargeY)
            local real dis = GetDistanceByXY(GetUnitX(dto.m_unit), GetUnitY(dto.m_unit), chargeX, chargeY)
            local real et = dto.getReals(5)
            local real x
            local real y
            local boolean bl = false
            local boolean isTerrian = dto.getBooleans(0)
            local boolean isObstacle = dto.getBooleans(1)
            local CallBack callback = 0
            if count > 0 then
                set count = count - 1
                call dto.setIntegers(0, count)

                if step < maxStep then
                    set step = step + dto.getReals(4)
                    call dto.setReals(2, step)
                else
                    call dto.setReals(2, maxStep)
                endif

                set x = GetUnitX(dto.m_unit) + step * Cos(ang * bj_DEGTORAD)
                set y = GetUnitY(dto.m_unit) + step * Sin(ang * bj_DEGTORAD)

                if (not (IsBeyondBound(x, y))) then
                    if isObstacle then
                        call EnumDestructablesInCircle(x, y, XE_MAX_COLLISION_SIZE, function thistype.anon_dc1095a3d366)
                    endif

                    if isTerrian then
                        set bl = true
                    elseif IsTerrainWalkable(x, y) then
                        set bl = true
                    endif

                    if bl then
                        call SetUnitX(dto.m_unit, x)
                        call SetUnitY(dto.m_unit, y)
                    endif
                endif

                //面向角度
                if faceModel == 0 then
                    call SetUnitFacing(dto.m_unit, ang)
                elseif faceModel == 1 then
                    call SetUnitFacing(dto.m_unit, ang + 180.0)
                endif

                //特效
                if dto.m_string != null and et > 0.0 then
                    if ModuloInteger(count, R2I(et / INTERVAL)) == 0 then
                        call DestroyEffect(AddSpecialEffectTarget(dto.m_string, dto.m_unit, "origin"))
                    endif
                endif

                if dis <= maxStep then
                    set callback = dto.m_int
                    if callback != 0 then
                        call callback.evaluate(dto.m_data)
                    endif
                    call dto.destroy()
                endif
            else
                set callback = dto.m_int
                if callback != 0 then
                    call callback.evaluate(dto.m_data)
                endif
                call dto.destroy()
            endif
        endmethod
        static method unitChargeToXY takes unit u, real x, real y, integer faceModel, real initSpeed, real maxSpeed, real acc, boolean isTerrian, /*
            */boolean isObstacle, string eff, real et, integer data, CallBack callback returns nothing
            local Dto dto = Dto.create()
            local real dis = GetDistanceByXY(GetUnitX(u), GetUnitY(u), x, y)
            local real avgspeed = (initSpeed + maxSpeed) / 2
            set dto.m_unit = u
            set dto.m_string = eff
            set dto.m_int = integer(callback)
            set dto.m_data = data
            call dto.setIntegers(0, R2I(dis / (avgspeed * INTERVAL)))
            call dto.setIntegers(1, faceModel)
            call dto.setReals(0, x)
            call dto.setReals(1, y)
            call dto.setReals(2, initSpeed * INTERVAL)
            call dto.setReals(3, maxSpeed * INTERVAL)
            call dto.setReals(4, acc * INTERVAL * INTERVAL)
            call dto.setReals(5, et)
            call dto.setBooleans(0, isTerrian)
            call dto.setBooleans(1, isObstacle)
            call TimerStart(dto.getTimer(), INTERVAL, true, function thistype.anon_2da922d02b6b)
        endmethod

    endstruct

endlibrary

